package com.gonsin.ta.logic.parse.serialize;

import com.gonsin.ta.logic.enums.StackState;
import com.gonsin.ta.logic.exceptions.TaException;
import com.gonsin.ta.logic.parse.condition.Condition;
import com.gonsin.ta.logic.parse.condition.Executable;
import com.gonsin.ta.logic.process.SignalCenter;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import static com.gonsin.ta.logic.enums.StackState.BEFORE_READY;
import static com.gonsin.ta.logic.enums.StackState.READY;

/**
 * 一次执行反序列化的上下文
 * 用于存储 一次反序列化过程中 上下文信息，包括必要的
 * 1、信号处理中心
 * 2、之前已经反序列化过的对象
 */
@Data
@Slf4j
public class DeserializeContext {

    /**
     * 信号处理中心
     */
    private SignalCenter signalCenter;


    /**
     * 嵌套方法放入堆栈中
     */
    private Map<String, Executable> stack;

    /**
     * 堆栈状态
     */
    private StackState stackState = BEFORE_READY;

    /**
     * 反序列化堆栈数据
     * @param stackDes 从数据库中获取到的堆栈
     */
    public void readyStack(Map<String, TaDeserializable> stackDes) {

        Map<String, Executable> finalStack = new HashMap<>();
        stackDes.forEach((conditionId, des) -> {
            finalStack.put(conditionId, des.toExecutable(this));
        });

        if(CollectionUtils.isEmpty(finalStack)){
            this.stack = finalStack;
            stackState = READY;
            return;
        }

        makeStackUntilReady(finalStack, 0);
        this.stack = finalStack;
        stackState = READY;
    }


    /**
     * 查找是否有未分配好的future堆栈，一直循环直到全部都分配好为止
     */
    private void makeStackUntilReady(Map<String, Executable> finalStack, int currentIndex){

        // 循环查询100次之后，如果还是有不存在的流程，则说明其他代码有问题，应该中断循环
        if(currentIndex > 100){
            throw new TaException("循环超过100次还是没法找到堆栈方法");
        }

        Set<String> keys = finalStack.keySet();
        for(String key : keys){
            Executable ex = finalStack.get(key);
            if(!(ex instanceof Condition)){
                log.error("TA - 按道理不能走到这里");
                continue;
            }

            Condition condition = (Condition) ex;
            boolean finished = condition.handleStack(finalStack);
            if(finished){
                break;
            }
            makeStackUntilReady(finalStack, currentIndex + 1);
        }
    }
}
